package com.soboot.common.config.job.listener;

import com.soboot.common.config.job.XxlJobGroup;
import com.soboot.common.config.job.XxlJobInfo;
import com.soboot.common.config.job.annotation.XxlJobAutoRegister;
import com.soboot.common.config.job.handler.AbstractJobHandler;
import com.soboot.common.config.job.service.JobGroupService;
import com.soboot.common.config.job.service.JobInfoService;
import com.soboot.log.utils.LogUtil;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @Author:
 * @createTime: 2023年01月28日 21:58:40
 * @version:
 * @Description:
 * @Copyright:
 */
public class AutoRegisterListener implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Autowired
    private JobGroupService jobGroupService;
    @Autowired
    private JobInfoService jobInfoService;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        addJobGroup();
        addJobInfo();
    }

    /**
     * 注册执行器
     */
    private void addJobGroup() {

        if (jobGroupService.checkGroup(null,null)) {
            return;
        }
        if(jobGroupService.registerGroup(null,null)) {
            LogUtil.info("auto register xxl-job group success!");
        }
    }

    /**
     * 注册任务
     */
    private void addJobInfo() {

        List<XxlJobGroup> jobGroups = jobGroupService.getJobGroup(null,null);
        XxlJobGroup xxlJobGroup = jobGroups.get(0);

        String[] beanDefinitionNames = applicationContext.getBeanNamesForType(AbstractJobHandler.class, false, true);
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanDefinitionName);

            Map<Method, XxlJob> annotatedMethods  = MethodIntrospector.selectMethods(bean.getClass(),
                    new MethodIntrospector.MetadataLookup<XxlJob>() {
                        @Override
                        public XxlJob inspect(Method method) {
                            return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
                        }
                    });
            for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
                Method executeMethod = methodXxlJobEntry.getKey();
                XxlJob xxlJob = methodXxlJobEntry.getValue();

                //自动注册
                if (executeMethod.isAnnotationPresent(XxlJobAutoRegister.class)) {
                    XxlJobAutoRegister xxlRegister = executeMethod.getAnnotation(XxlJobAutoRegister.class);
                    List<XxlJobInfo> jobInfo = jobInfoService.getJobInfo(xxlJobGroup.getId(), xxlJob.value());
                    if (!jobInfo.isEmpty()){
                        Optional<XxlJobInfo> first = jobInfo.stream()
                                .filter(xxlJobInfo -> xxlJobInfo.getExecutorHandler().equals(xxlJob.value()))
                                .findFirst();
                        if (first.isPresent()) {
                            continue;
                        }
                    }

                    XxlJobInfo xxlJobInfo = createXxlJobInfo(xxlJobGroup, xxlJob, xxlRegister);
                    Integer jobInfoId = jobInfoService.addJobInfo(xxlJobInfo);
                }
            }
        }
    }

    private XxlJobInfo createXxlJobInfo(XxlJobGroup xxlJobGroup,XxlJob xxlJob,XxlJobAutoRegister xxlJobAutoRegister){

        XxlJobInfo xxlJobInfo = XxlJobInfo.builder()
                .jobGroup(xxlJobGroup.getId())
                .scheduleType("CRON")
                .scheduleConf(xxlJobAutoRegister.cron())
                .misfireStrategy("DO_NOTHING")
                .author(xxlJobAutoRegister.author())
                .jobDesc(xxlJobAutoRegister.jobDesc())
                .triggerStatus(xxlJobAutoRegister.triggerStatus())
                .executorHandler(xxlJob.value())
                .executorRouteStrategy(xxlJobAutoRegister.routeStrategy())
                .executorTimeout(0)
                .executorBlockStrategy("SERIAL_EXECUTION")
                .glueType("BEAN")
                .build();

        return xxlJobInfo;
    }
}
